/**
 * @file RetroreflectionClient.c
 * @author haiming
 * @brief 单行回射程序客户端
 * @version 0.1
 * @date 2022-07-19
 * 
 * @copyright Copyright (c) 2022
 * 
 */

#include "SocketTimeOut.h"
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>

void echo_client_rt(FILE* fp, int sockfd, int nsec);
void echo_cli_opt(FILE* fp, int sockfd, int msec);
void str_cli_pth(FILE* fp_arg, int sockfd_arg);
void *copyto(void *arg);

void str_cli(FILE* fp, int sockfd)
{
    printf("str_cli. [%s,%d]\n",__FILE__, __LINE__);
    char sendline[MAXLEN] = {0}, recvline[MAXLEN] = {0};

    while (fgets(sendline, MAXLEN, fp) != NULL)
    {
        write(sockfd, sendline, strlen(sendline));
        printf("client :%s\n", sendline);
        if(read(sockfd, recvline, MAXLEN) <= 0)
        {
            printf("str_cli : server terminated prematurely\n");
            break;
        }
        // printf("server :%s\n", recvline);
        memset(sendline, 0, sizeof(sendline));
        memset(recvline, 0, sizeof(recvline));
    }
}

#include <sys/select.h>
#define max(a, b)       (((a) > (b)) ? (a) : (b))

static void select_alarm(void)
{
    printf("select alarm\n");
}
void str_cli_select(FILE* fp, int sockfd)
{
    printf("str_cli_select. [%s,%d]\n",__FILE__, __LINE__);
    int maxfdpl;
    fd_set rset;
    char sendline[MAXLEN] = {0}, recvline[MAXLEN] = {0};
    // SIG_HANDLER* sigfunc = signal(SIGALRM, select_alarm);

    FD_ZERO(&rset);
    for (;;)
    {
        FD_SET(fileno(fp), &rset);
        FD_SET(sockfd, &rset);
        maxfdpl = max(fileno(fp), sockfd) + 1;
        // alarm(2);
        int res = select(maxfdpl, &rset, NULL, NULL, NULL);
        if(res < 0 && errno == EINTR)
        {
            printf("errno :%u\n", errno);
            continue;
        }

        if(FD_ISSET(sockfd, &rset))
        {
            int nRecv = read(sockfd, recvline, MAXLEN);
            if(nRecv > 0)
            {
                // printf("server :%s\n",recvline);
            }
            else
            {
                printf("str_cli_select: read error! nRecv :%d\n",nRecv);
                exit(1);
                // pr_cpu_time();
                // return ;
            }
            // alarm(0);
        }

        if(FD_ISSET(fileno(fp), &rset))
        {
            if(fgets(sendline, MAXLEN, fp) == NULL)
            {
                printf("end of inputer!\n");
                pr_cpu_time();
                return ;
            }
            else
            {
                printf("client :%s\n", sendline);
            }
            write(sockfd, sendline, strlen(sendline));
            // alarm(0);
        }
        memset(sendline, 0, sizeof(sendline));
        memset(recvline, 0, sizeof(recvline));        
    }
    // alarm(0);
    // signal(SIGALRM, sigfunc);
}

void str_cli_shutdown(FILE* fp, int sockfd)
{
    printf("str_cli_shutdown. [%s,%d]\n",__FILE__, __LINE__);
}
char* strupr(char* str)
{
    char* p = str;
    if(NULL != str)
    {
        for (size_t i = 0; i < strlen(str); i++)
        {
            if(str[i] >= 'a' && str[i] <= 'z')
            {
                p[i] += ('A' - 'a') ;
            }
        }
    }
    return p;
}
int main(int argc, char** argv)
{
    printf("Retroreflection Client: you are welcome!\n");
    int sockfd;
    struct sockaddr_in servaddr;
    if (argc < 2)
    {
        printf("usage : %s <ipaddress> <1/2/3/4/5/6>\n", *argv);
        return -1;
    }
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERV_PORT);
    int ret = inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
    if (ret !=1 )
    {
        printf("ret :%d\n", ret);
        return -1;
    }
    
    int nConn = connect(sockfd, (SA*)&servaddr, sizeof(servaddr));//connect_timeout(sockfd, (SA*)&servaddr, sizeof(servaddr), 3);
    if(nConn == 0)
    {
        const char* filepath = "./resource/demo.xml";
        FILE* fp = fopen(filepath, "r");
        if (NULL == fp)
        {
            printf("open error, file path :%s\n", filepath);
        }        
        if(argc == 3 && *argv[2] == '1')
        {
            str_cli_select(stdin, sockfd);
        }
        else if(argc == 3 && *argv[2] == '2')
        {
            str_cli_shutdown(fp, sockfd);
        }
        else if (argc == 3 && *argv[2] == '3')
        {
            echo_client_rt(fp, sockfd, 5);
        }
        else if(argc ==3 && *argv[2] == '4')
        {
            echo_client_alarm(stdin, sockfd, 5);
        }
        else if(argc ==3 && *argv[2] == '5')
        {
            echo_cli_opt(fp, sockfd, 5*1000);
        }
        else if(argc == 3 && *argv[2] == '6')
        {
            str_cli_pth(fp, sockfd);
        }
        else
        {
            str_cli(fp, sockfd);
            // printf("cmd error\n");
            // printf("addr :%u\n", servaddr.sin_addr.s_addr);
        }
    }
    else
    {
        printf("dest ip :%s, connect error :%s\n", argv[1], strerror(errno));
    }

    return nConn;
}

void echo_client_rt(FILE* fp, int sockfd, int nsec)
{
    int n;
    char sendline[MAXLEN], recvline[MAXLEN+1];
    while (fgets(sendline, MAXLEN, fp) != NULL)
    {
        write(sockfd, sendline, strlen(sendline));
        printf("client line :%s\n", sendline);
        int res;
        while ((res = readable_timeo(sockfd, nsec)) == 0)
        {
            printf("socket timeout.[%s:%s:%d]\n", __FILE__, __FUNCTION__, __LINE__);
        }
        if (res >0)
        {
            n = read(sockfd, recvline, MAXLEN);
            recvline[n] = 0;
            // printf("recv line :%s[%s:%s:%d]\n", recvline, __FILE__, __FUNCTION__, __LINE__);
        }        
        else
        {
            printf("select error code :%u\t%s", errno, strerror(errno));
        }
        memset(sendline, 0, sizeof(sendline));
        memset(recvline, 0, sizeof(recvline));        
    }
}

void echo_cli_opt(FILE* fp, int sockfd, int msec)
{
    set_recv_timeo(&sockfd, msec);
    int n;
    char sendline[MAXLEN], recvline[MAXLEN+1];
    while (fgets(sendline, MAXLEN, fp) != NULL)
    {
        write(sockfd, sendline, strlen(sendline));
        printf("client line :%s\n", sendline);
        do
        {
            n = read(sockfd, recvline, MAXLEN);
            if (n >0)
            {
                break;
            }
            else
            {
                printf("error code :%u\tmsg :%s\n", errno, strerror(errno));
            }
        }while(EAGAIN == errno && n < 0);
        recvline[n] = 0;
        // printf("recv line :%s\n", recvline);
        memset(sendline, 0, sizeof(sendline));
        memset(recvline, 0, sizeof(recvline));        
    }
}

static int s_sockfd;
void str_cli_pth(FILE* fp, int sockfd)
{
    char recvline[MAXLEN] = {0};
    pthread_t tid;
    s_sockfd = sockfd;
    pthread_create(&tid, NULL, copyto, fp);
    while(read(sockfd, recvline, MAXLEN-1) > 0)
    {
        memset(recvline, 0, sizeof(recvline));
    }
}


void *copyto(void *arg)
{
    int sockfd = s_sockfd;
    FILE* fp = (FILE*) arg;
    if(NULL != fp)
    {
        char sendline[MAXLEN];
        while(fgets(sendline, MAXLEN, fp) != NULL)
        {
            printf("client :%s\n", sendline);
            write(sockfd, sendline, strlen(sendline));
        }
        shutdown(sockfd, SHUT_WR);
    }
    return NULL;
}